package com.hzb.erp.wechat.controller;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import cn.binarywang.wx.miniapp.bean.WxMaUserInfo;
import cn.binarywang.wx.miniapp.util.WxMaConfigHolder;
import com.hzb.erp.common.entity.User;
import com.hzb.erp.common.entity.WxAccess;
import com.hzb.erp.common.service.UserService;
import com.hzb.erp.configuration.SystemConfig;
import com.hzb.erp.exception.BizException;
import com.hzb.erp.security.Util.JwtUserDetails;
import com.hzb.erp.security.Util.SecurityUtils;
import com.hzb.erp.security.service.impl.UserUserDetailsService;
import com.hzb.erp.wechat.pojo.WxMaLoginDTO;
import com.hzb.erp.wechat.service.MiniappService;
import com.hzb.erp.wechat.service.WxAccessService;
import com.hzb.erp.wechat.utils.JsonResponse;
import com.hzb.erp.wechat.utils.JsonResponseUtil;
import com.hzb.erp.wechat.utils.JsonUtils;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.bean.WxOAuth2UserInfo;
import me.chanjar.weixin.common.error.WxErrorException;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.Map;

/**
 * 微信小程序用户接口
 *
 */
@RestController
@AllArgsConstructor
@Slf4j
@RequestMapping("/wx/maportal")
public class MiniappUserController {

    private final WxMaService wxMaService;
    private final WxAccessService wxAccessService;
    private final UserService userService;
    private final UserUserDetailsService userUserDetailsService;
    /**
     * 登陆接口
     */
    @PostMapping("/login")
    public JsonResponse<Object> login(@RequestBody WxMaLoginDTO loginDTO) {

        MiniappService.setConfig(wxMaService);
        String appid = MiniappService.getDefaultAppId();

        if (StringUtils.isBlank(loginDTO.getCode())) {
            return JsonResponseUtil.error("缺少参数code");
        }
        if (!wxMaService.switchover(appid)) {
            throw new IllegalArgumentException(String.format("未找到对应appid=[%s]的配置，请核实！", appid));
        }
        WxMaJscode2SessionResult session = loginSession(appid, loginDTO.getCode());
        log.info(session.getSessionKey());
        log.info(session.getOpenid());

        WxOAuth2UserInfo userInfo = new WxOAuth2UserInfo();
        userInfo.setOpenid(session.getOpenid());
        userInfo.setUnionId(session.getUnionid());
        userInfo.setNickname(loginDTO.getNickName());
        userInfo.setSex(loginDTO.getGender());
        userInfo.setCity(loginDTO.getCity());
        userInfo.setProvince(loginDTO.getProvince());
        userInfo.setCountry(loginDTO.getCountry());
        userInfo.setHeadImgUrl(loginDTO.getAvatarUrl());
        userInfo.setHeadImgUrl(loginDTO.getAvatarUrl());

        WxAccess wxAccess = wxAccessService.getOrSaveRecord(userInfo, "mp");

        Map<String, Object> res = new HashMap<>();
        res.put("openid", session.getOpenid());
        res.put("wxaccessid", wxAccess.getId());
        res.put("token", this.attemptGetStudentToken(wxAccess.getId()) );

        return JsonResponseUtil.data(res);
    }

    private WxMaJscode2SessionResult loginSession(String appid, String code) {
        if (!wxMaService.switchover(appid)) {
            throw new IllegalArgumentException(String.format("未找到对应appid=[%s]的配置，请核实！", appid));
        }
        try {
            return wxMaService.getUserService().getSessionInfo(code);
        } catch (WxErrorException e) {
            log.error(e.getMessage(), e);
            throw new BizException(e.toString());
        } finally {
            WxMaConfigHolder.remove();//清理ThreadLocal
        }
    }

    /**
    * 尝试获取登录token，当该微信账号没有登录过的时候会获取不到，前端会有提示
    * */
    private String attemptGetStudentToken(Long wxAccessId) {
        User wxuser = userService.getByWxAccessId(wxAccessId);
        if (wxuser != null) {
            JwtUserDetails userDetails = userUserDetailsService.loadUserByUsername(wxuser.getMobile());
            if (userDetails != null) {
                SecurityUtils.setStudentRole(userDetails);
                SecurityUtils.checkUserDetails(userDetails);
            }
            return SecurityUtils.generateToken(userDetails, SystemConfig.getJwtExpiredTtlSec());
        }
        return "";
    }

    /**
     * <pre>
     * 获取用户信息接口
     * </pre>
     */
    @GetMapping("/info")
    public String info(String sessionKey,
                       String signature, String rawData, String encryptedData, String iv) {

        MiniappService.setConfig(wxMaService);
        String appid = MiniappService.getDefaultAppId();

        if (!wxMaService.switchover(appid)) {
            throw new IllegalArgumentException(String.format("未找到对应appid=[%s]的配置，请核实！", appid));
        }

        // 用户信息校验
        if (!wxMaService.getUserService().checkUserInfo(sessionKey, rawData, signature)) {
            WxMaConfigHolder.remove();//清理ThreadLocal
            return "user check failed";
        }

        // 解密用户信息
        WxMaUserInfo userInfo = wxMaService.getUserService().getUserInfo(sessionKey, encryptedData, iv);
        WxMaConfigHolder.remove();//清理ThreadLocal
        return JsonUtils.toJson(userInfo);
    }

    /**
     * <pre>
     * 获取用户绑定手机号信息
     * </pre>
     */
    @GetMapping("/phone")
    public String phone(String sessionKey, String signature,
                        String rawData, String encryptedData, String iv) {

        MiniappService.setConfig(wxMaService);
        String appid = MiniappService.getDefaultAppId();

        if (!wxMaService.switchover(appid)) {
            throw new IllegalArgumentException(String.format("未找到对应appid=[%s]的配置，请核实！", appid));
        }

        // 用户信息校验
        if (!wxMaService.getUserService().checkUserInfo(sessionKey, rawData, signature)) {
            WxMaConfigHolder.remove();//清理ThreadLocal
            return "user check failed";
        }

        // 解密
        WxMaPhoneNumberInfo phoneNoInfo = wxMaService.getUserService().getPhoneNoInfo(sessionKey, encryptedData, iv);
        WxMaConfigHolder.remove();//清理ThreadLocal
        return JsonUtils.toJson(phoneNoInfo);
    }

}
